﻿//        private Plan HeurSearch(List<Condition> initials, List<Condition> goals,
//            List<Task> availableTasks, Plan result)
//        {
//            // Алгоритм работает, пока не кончатся задачи
//            while (availableTasks.Count > 0)
//            {
//                // Пересчитываем метрики условий и задач
//                ReEvaluate(goals, initials, availableTasks);

//                // Берём лучшую задачу
//                Task bestTask = GetTheBestTask(availableTasks);

//                if (bestTask == null)
//                {
//                    // Ценные задачи закончились - возвращено значение null
//                    return null;
//                }
//                else
//                {

//                    // Найдя ценную задачу, идём вглубь
//                    // Для этого нужно преобразовать пост-условия
//                    List<Condition> newGoals = new List<Condition>();
//                    newGoals.AddRange(goals);

//                    // Добавляем новые (пред-условия новой задачи)
//                    foreach (Condition addedGoal in bestTask.PreConditions)
//                    {
//                        // Проверка на случай если добавляемое условие уже доступно
//                        if ((!initials.Contains(addedGoal)) && (!goals.Contains(addedGoal)))
//                        {
//                            newGoals.Add(addedGoal);
//                        }
//                    }

//                    // Удаляем достигнутые цели
//                    foreach (Condition reachedGoal in bestTask.PostConditions)
//                    {
//                        newGoals.Remove(reachedGoal);
//                    }
//                    // Добавляем задачу в начало плана
//                    if (result.Tasks.Contains(bestTask))
//                    {
//                        // Если добавляемая задача уже присутствует в плане, 
//                        // надо её удалить в вставить в начала
//                        result.Tasks.Remove(bestTask);
//                    }
//                    result.Tasks.Insert(0, bestTask);
//                    //Log.Write("insert" + bestTask.ID.ToString());

//                    // Проверяем необходимость продлжать рекурсию
//                    if (newGoals.Count == 0)
//                    {
//                        // Мы достигли успеха (выполнены все условия) - возвращаем результат
//                        return result;
//                    }
//                    else
//                    {
//                        // К цели мы пока не пришли

//                        // Необходимо также исключить выбранную задачу из рассмотрения
//                        List<Task> newAvailableTasks = new List<Task>();
//                        newAvailableTasks.AddRange(this.curBase.AvailableTasks);
//                        //foreach (Task plannedTask in result.Tasks)
//                        //{
//                        //    newAvailableTasks.Remove(plannedTask);
//                        //}
//                        newAvailableTasks.Remove(bestTask);

//                        // Рекурсивно вызываем данный метод для новых условий
//                        Plan recResult = HeurSearch(initials, newGoals, newAvailableTasks, result);

//                        // Рекурсивный результат будет нулевым (null) только в том слуае, если движение 
//                        // по этой ветви не приводит к решению (на каком-то шаге закончились ценные задачи)
//                        if (recResult == null)
//                        {

//                            // Если мы вышли из метода, то путь не был найден - надо удалить из плана эту задачу
//                            result.Tasks.Remove(bestTask);

//                            //Log.Write("remove" + bestTask.ID.ToString());

//                            // Если развитие плана, содержавшего данную задачу, 
//                            // привело к лаже, такая задача нам не нужна
//                            availableTasks.Remove(bestTask);

//                        }
//                        else
//                        {
//                            // Если решение было найдено - всё круто! :)
//                            return recResult;
//                        }
//                    }
//                }


//            }

//            // Задачи кончились, а до результата мы не дошли
//            return null;
//        }


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Qas.CommonLogic.BusinessObjects;
using Qas.CommonLogic;

namespace Qas.User.Keepers
{
    /// <summary>
    /// Класс, реализующий алгоритмы эвристического поиска   
    /// </summary>
    /// <remarks>
    /// Реализация строится на базе регрессивного перебора цепочек задач
    /// </remarks>
    public class HeurKeeper : AbstractKeeper
    {
        /// <summary>
        /// Доступные в рамках системы задачи
        /// </summary>
        List<Task> availableTasks = new List<Task>();

        /// <summary>
        /// Задачи, не имеющие предусловий
        /// </summary>
        List<Task> freeTasks = new List<Task>();

        /// <summary>
        /// Конструктор эвристического поисковика
        /// </summary>
        /// <param name="currentBase">Используемая база</param>
        public HeurKeeper(Base currentBase)
            : base(currentBase)
        {
            this.avaiableBudget = 9999999;
        }

        public override List<Plan> Search(List<Task> tasks,
            List<Condition> initConditions, List<Condition> goalConditions)
        {
            // Инициализация переменных: начальное и целевое состояния
            this.initialState = initConditions;
            this.goalState = goalConditions;



            // Доступные задачи
            this.availableTasks = tasks;

            List<Condition> newInitCond = new List<Condition>(); //?                        

            #region 1
            // Отдельная обработка случая, когда начальное состояние - пусто
            //
            //if ((initConditions.Count == 0))
            //{
            //    // Если начальное состояние не содержит условий
            //    foreach (Task task in tasks)
            //    {
            //        // Находим все задачи, которые могут быть выполнены (число предусловий - 0)
            //        if (task.PreConditions.Count == 0)
            //        {
            //            // Добавляем в список "свободных" задач
            //            freeTasks.Add(task);

            //            // Расширяем список возможных начальных условий
            //            newInitCond.AddRange(task.PostConditions);
            //        }
            //    }

            //    if (freeTasks.Count != 0)
            //    {
            //        this.initialState = newInitCond;
            //    }
            //    else
            //    {
            //        //MessageBox.Show("Выберите начальное предусловие!");
            //        //return searchResult;
            //    }
            //}            


            //else
            //{
            //    #region Локальная частная нелогичная оптимизация
            //    // Берём условие с минимальным идентификатором
            //    Condition cSmallest = initConditions[0];

            //    foreach (Condition cond in initConditions)
            //    {
            //        if (cond.ID <= cSmallest.ID)
            //        {
            //            cSmallest = cond;
            //        }
            //    }

            //    List<Task> tToDel = new List<Task>(); //?

            //    // Копируем в этот список все доступные задачи
            //    tToDel.AddRange(tasks);

            //    foreach (Task task in tToDel)
            //    {
            //        foreach (Condition cond in task.PreConditions)
            //        {
            //            if (cond.ID < cSmallest.ID)
            //            {
            //                tasks.Remove(task);
            //                break;
            //            }
            //        }
            //    }
            //    #endregion
            //}
            #endregion

            // Возвращаемый результат
            List<Plan> searchResult = new List<Plan>();

            // Оцениваем все условия
            foreach (Condition conditionItem in this.curBase.AvailableConditions)
            {
                conditionItem.Evaluate(tasks);
            }

            // Оцениваем задачи
            foreach (Task taskItem in tasks)
            {
                taskItem.Evaluate(this.goalState);
            }

            ////List<int> indexesToRemove = new List<int>();
            Plan heurPlan = HeurSearch(initConditions, goalConditions, tasks, new Plan());
            //for (int i = 0; i < heurPlan.Tasks.Count; i++)
            //{

            //}

            searchResult.Add(heurPlan);


            return searchResult;
        }




        /// <summary>
        /// Эвристический поиск на базе регрессивного перебора цепочек задач
        /// </summary>
        /// <param name="goals">Цели - целевое состояние</param>
        /// <param name="availableTasks">Доступные задачи</param>
        /// <param name="results">Накапливаемый список результатов</param>
        /// <returns></returns>
        private Plan HeurSearch(List<Condition> initials, List<Condition> goals,
            List<Task> availableTasks, Plan result)
        {
            // Алгоритм работает, пока не кончатся задачи
            while (availableTasks.Count > 0)
            {
                // Берём лучшую задачу
                Task bestTask = GetTheBestTask(availableTasks);

                if (bestTask == null)
                {
                    // Ценные задачи закончились - возвращено значение null
                    return null;
                }
                else
                {
                    List<Condition> addedGoals = new List<Condition>();
                    // Найдя ценную задачу, идём вглубь
                    // Для этого нужно преобразовать пост-условия
                    List<Condition> newGoals = new List<Condition>();
                    newGoals.AddRange(goals);

                    // Добавляем новые (пред-условия новой задачи)
                    foreach (Condition addedGoal in bestTask.PreConditions)
                    {
                        // Проверка на случай если добавляемое условие уже доступно
                        if ((!initials.Contains(addedGoal)) && (!goals.Contains(addedGoal)))
                        {
                            newGoals.Add(addedGoal);
                            addedGoal.UnDone(availableTasks);
                        }
                    }

                    List<Condition> removedGoals = new List<Condition>();
                    // Удаляем достигнутые цели
                    foreach (Condition reachedGoal in bestTask.PostConditions)
                    {
                        newGoals.Remove(reachedGoal);
                        reachedGoal.Done(availableTasks);
                    }
                    // Добавляем задачу в начало плана
                    if (result.Tasks.Contains(bestTask))
                    {
                        // Если добавляемая задача уже присутствует в плане, 
                        // надо её удалить в вставить в начала
                        result.Tasks.Remove(bestTask);
                    }
                    result.Tasks.Insert(0, bestTask); 
                    //result.Tasks.Add(bestTask);// оптимизировать

                    // Проверяем необходимость продлжать рекурсию
                    if (newGoals.Count == 0)
                    {
                        // Мы достигли успеха (выполнены все условия) - возвращаем результат
                        return result;
                    }
                    else
                    {
                        // К цели мы пока не пришли

                        // Необходимо также исключить выбранную задачу из рассмотрения
                        List<Task> newAvailableTasks = new List<Task>();
                        newAvailableTasks.AddRange(this.availableTasks);

                        newAvailableTasks.Remove(bestTask);

                        // Рекурсивно вызываем данный метод для новых условий
                        Plan recResult = HeurSearch(initials, newGoals, newAvailableTasks, result);

                        // Рекурсивный результат будет нулевым (null) только в том слуае, если движение 
                        // по этой ветви не приводит к решению (на каком-то шаге закончились ценные задачи)
                        if (recResult == null)
                        {

                            // Если мы вышли из метода, то путь не был найден - надо удалить из плана эту задачу
                            result.Tasks.Remove(bestTask);

                            //Log.Write("remove" + bestTask.ID.ToString());

                            // Если развитие плана, содержавшего данную задачу, 
                            // привело к лаже, такая задача нам не нужна
                            availableTasks.Remove(bestTask);

                        }
                        else
                        {
                            // Если решение было найдено - всё круто! :)
                            return recResult;
                        }
                    }
                }


            }

            // Задачи кончились, а до результата мы не дошли
            return null;
        }

        /// <summary>
        /// Пересчёт значений для условий и задач
        /// </summary>        
        private void ReEvaluate(List<Condition> addedGoals, List<Condition> removedGoals, List<Task> tasks)
        {
            //foreach (Condition conditionItem in curBase.AvailableConditions)
            //{
            //    conditionItem.Evaluate(tasks);
            //}         
        }

        /// <summary>
        /// Поиск лучшей задачи из числа возможных
        /// </summary>
        /// <param name="availableTasks">Доступные задачи</param>
        /// <returns>Лучшая доступная задача</returns>
        private Task GetTheBestTask(List<Task> availableTasks)
        {
            if (availableTasks.Count == 0)
            {
                return null;
            }

            Task bestTask = availableTasks[0];
            foreach (Task taskItem in availableTasks)
            {

                if (bestTask.Value == taskItem.Value)
                {
                    if (bestTask.Accessibility < taskItem.Accessibility)
                    {
                        bestTask = taskItem;
                    }
                }

                if (bestTask.Value < taskItem.Value)
                {

                    bestTask = taskItem;
                }

            }

            if (bestTask.Value == 0)
            {
                return null;
            }

            return bestTask;
        }

        ///// <summary>
        ///// Поиск лучшей задачи из числа возможных
        ///// </summary>
        ///// <param name="availableTasks">Доступные задачи</param>
        ///// <returns>Лучшая доступная задача</returns>
        //private Task GetTheBestTask(List<Condition> goals)
        //{
        //    if (goals[0].ProducingTasks.Count == 0)
        //    {
        //        if (availableTasks.Count == 0)
        //        {
        //            return null;
        //        }

        //        Task bestTask = availableTasks[0];
        //        foreach (Task taskItem in availableTasks)
        //        {

        //            if (bestTask.Value == taskItem.Value)
        //            {
        //                if (bestTask.Accessibility < taskItem.Accessibility)
        //                {
        //                    bestTask = taskItem;
        //                }
        //            }

        //            if (bestTask.Value < taskItem.Value)
        //            {

        //                bestTask = taskItem;
        //            }

        //        }

        //        if (bestTask.Value == 0)
        //        {
        //            return null;
        //        }

        //        return bestTask;
        //    }
        //    else
        //    {

        //        Task bestTask = goals[0].ProducingTasks[0];

        //        foreach (Condition goal in goals)
        //        {
        //            foreach (Task taskItem in goal.ProducingTasks)
        //            {

        //                if (bestTask.Value == taskItem.Value)
        //                {
        //                    if (bestTask.Accessibility < taskItem.Accessibility)
        //                    {
        //                        bestTask = taskItem;
        //                    }
        //                }

        //                if (bestTask.Value < taskItem.Value)
        //                {

        //                    bestTask = taskItem;
        //                }

        //            }
        //        }


        //        if (bestTask.Value == 0)
        //        {
        //            return null;
        //        }

        //        return bestTask;
        //    }
        //}


        /// <summary>
        /// Подсчет стоимости набора задач
        /// </summary>
        private double CountCost(List<Task> tasks)
        {
            double sum = 0;

            foreach (Task task in tasks)
            {
                sum += task.PDCost.Expectancy;
            }

            return sum;
        }

        /// <summary>
        /// Проверка на возможность существования задачи в контексте данных постусловий
        /// Применяется в BackwardSearch поиске
        /// </summary>
        private bool TaskCanBeStartedPost(List<Condition> postConditions, Task task)
        {
            foreach (Condition cond in postConditions)
            {
                if (task.PostConditions.Contains(cond))
                {
                    return true;
                }
            }

            return false;
        }
    }
}
